{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "54bd32c5",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-12-09T06:52:38.038063Z",
     "start_time": "2023-12-09T06:52:37.104554Z"
    },
    "execution": {
     "iopub.execute_input": "2024-05-02T10:55:57.948864Z",
     "iopub.status.busy": "2024-05-02T10:55:57.948502Z",
     "iopub.status.idle": "2024-05-02T10:56:00.801292Z",
     "shell.execute_reply": "2024-05-02T10:56:00.800651Z",
     "shell.execute_reply.started": "2024-05-02T10:55:57.948840Z"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import scipy.fft as fft\n",
    "import cv2\n",
    "import matplotlib.pyplot as plt\n",
    "import os\n",
    "from tqdm import tqdm\n",
    "import pandas as pd\n",
    "from cv2 import dct"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "2f270776",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-12-09T07:35:19.444806Z",
     "start_time": "2023-12-09T07:35:19.430842Z"
    },
    "execution": {
     "iopub.execute_input": "2024-05-02T10:56:39.205163Z",
     "iopub.status.busy": "2024-05-02T10:56:39.204848Z",
     "iopub.status.idle": "2024-05-02T10:56:39.266430Z",
     "shell.execute_reply": "2024-05-02T10:56:39.265879Z",
     "shell.execute_reply.started": "2024-05-02T10:56:39.205138Z"
    },
    "scrolled": true,
    "tags": []
   },
   "outputs": [],
   "source": [
    "def image_hash(img_path):\n",
    "    img = processing(img_path)\n",
    "    C_r_list = image_feature(img)\n",
    "    h_i = gen_hashing(C_r_list)\n",
    "    return h_i\n",
    "\n",
    "def processing(img_path):\n",
    "    \"\"\"\n",
    "    input：图片的路径\n",
    "    output：处理后的RGB图片\n",
    "    \"\"\"\n",
    "    try:\n",
    "        img = cv2.imread(img_path)\n",
    "        x = img.shape[0]//2 # 高度\n",
    "        y = img.shape[1]//2 # 宽度\n",
    "        Min = x if x<y else y\n",
    "        cropped_image = img[x-Min:x+Min, y-Min:y+Min] # 裁剪图像\n",
    "        img = cv2.resize((cropped_image), (512,512), interpolation=cv2.INTER_LINEAR)\n",
    "    except:\n",
    "        img = imageio.mimread(img_path)\n",
    "        img = np.array(img)\n",
    "        img = img[0]\n",
    "        img = img[:, :, 0:3]\n",
    "        x = img.shape[0]//2 # 高度\n",
    "        y = img.shape[1]//2 # 宽度\n",
    "        Min = x if x<y else y\n",
    "        cropped_image = img[x-Min:x+Min, y-Min:y+Min] # 裁剪图像\n",
    "        img = cv2.resize((cropped_image), (512,512), interpolation=cv2.INTER_LINEAR)\n",
    "#     out = cv2.GaussianBlur(img, (3, 3),1.3) # 使用python自带的高斯滤波\n",
    "    kernel = np.array([[1,2,1],[2,4,2],[1,2,1]])/16\n",
    "    out = cv2.filter2D(img, -1 , kernel=kernel)  # 二维滤波器\n",
    "    out = cv2.cvtColor(out, cv2.COLOR_BGR2YCrCb)\n",
    "    return out\n",
    "\n",
    "def image_feature(img):\n",
    "    \"\"\"\n",
    "    iamge:(512,512,3)\n",
    "    return: array格式(x,64,64)\n",
    "    \"\"\"\n",
    "    C_r_list = np.zeros((0,64,64)).tolist()\n",
    "    for i in range(0,512,64):\n",
    "        for j in range(0,512,64):\n",
    "            image_block = img[i:i+64,j:j+64,:]\n",
    "            C_r,C_i,C_j,C_k = QDCT(image_block) # 可以在这里取出实部和三个虚数的实部\n",
    "            C_r_list.append(np.sqrt(C_r**2+C_i**2+C_j**2+C_k**2).tolist())\n",
    "            # C_r_list.append(cv2.dct(np.float32(image_block[:,:,0])))\n",
    "    return np.array(C_r_list)\n",
    "\n",
    "def gen_hashing(feature_matrix):\n",
    "    \"\"\"\n",
    "    生成图像哈希值,和原论文不同，我的P和Q矩阵是每一行代表一个图像块。\n",
    "    input:array (x,64,64)\n",
    "    output:list (x)\n",
    "    \"\"\"\n",
    "    d_i = []\n",
    "    h_i = []\n",
    "    P_matrix = np.zeros((0,32)).tolist()\n",
    "    Q_matrix = np.zeros((0,32)).tolist()\n",
    "    for i in feature_matrix:\n",
    "        i = np.array(i)\n",
    "        row = i[0,1:33].reshape(1,-1)\n",
    "        column = i[1:33,0].reshape(1,-1)\n",
    "        P_matrix.extend(row.tolist())\n",
    "        Q_matrix.extend(column.tolist())\n",
    "    P_matrix = np.array(P_matrix)\n",
    "    Q_matrix = np.array(Q_matrix)\n",
    "    P_matrix_1 = (P_matrix - np.mean(P_matrix,axis = 0))/np.std(P_matrix,axis = 0,ddof=1)\n",
    "    Q_matrix_1 = (Q_matrix - np.mean(Q_matrix,axis = 0))/np.std(Q_matrix,axis = 0,ddof=1)\n",
    "    d_i = np.sqrt(np.sum((P_matrix_1 - Q_matrix_1)**2,axis = 1))\n",
    "    median = np.median(d_i)\n",
    "    for i in d_i:\n",
    "        if i < median:\n",
    "            h_i.append(0)\n",
    "        else:\n",
    "            h_i.append(1)\n",
    "    return np.array(h_i)\n",
    "\n",
    "def QDCT(img):\n",
    "    \"\"\"\n",
    "    img：(64,64,3)\n",
    "    \"\"\"\n",
    "    # C_r = DCT(img[:,:,0]+img[:,:,1]+img[:,:,2]) * (- 1 / np.sqrt(3))\n",
    "    Y = cv2.cvtColor(img, cv2.COLOR_RGB2YUV)[:,:,0]\n",
    "    V_blk = np.sum((Y-np.mean(Y))**2)/(img.shape[0]**2)\n",
    "    C_r = cv2.dct(np.float32(img[:,:,0]+img[:,:,1]+img[:,:,2]) * (- 1 / np.sqrt(3)))\n",
    "    C_i = cv2.dct(np.float32(img[:,:,2]-img[:,:,1]+V_blk) * (1 / np.sqrt(3)))\n",
    "    C_j = cv2.dct(np.float32(img[:,:,0]-img[:,:,2]+V_blk) * (1 / np.sqrt(3)))\n",
    "    C_k = cv2.dct(np.float32(img[:,:,1]-img[:,:,0]+V_blk) * (1 / np.sqrt(3)))\n",
    "    # C_i = DCT(img[:,:,2]-img[:,:,1]) * (1 / np.sqrt(3))\n",
    "    # C_j = DCT(img[:,:,0]-img[:,:,2]) * (1 / np.sqrt(3))\n",
    "    # C_k = DCT(img[:,:,1]-img[:,:,0]) * (1 / np.sqrt(3))\n",
    "    return C_r,C_i,C_j,C_k\n",
    "\n",
    "def DCT(X):\n",
    "    def gen_Matrix(N):\n",
    "        Matrix = np.zeros((N,N),dtype=float)\n",
    "        for row in range(N):#遍历行\n",
    "            if row == 0:#第一行\n",
    "                for col in range(N):\n",
    "                    Matrix[row,col] = 1 / np.sqrt(N)\n",
    "            else:\n",
    "                for col in range(N):\n",
    "                    Matrix[row,col] = np.sqrt(2/N) * (np.cos( (np.pi * (2*col+1) * row) / (2*N)))\n",
    "        return Matrix\n",
    "    Size = list(X.shape)\n",
    "    Rows,Cols = Size[0],Size[1]\n",
    "    A = gen_Matrix(Rows)\n",
    "    B = gen_Matrix(Cols)\n",
    "    B = B.T\n",
    "    T = np.dot(np.dot(A,X),B)\n",
    "    return T\n",
    "    \n",
    "def dist_img(h1,h2):\n",
    "    return sum(np.abs(h1-h2))\n",
    "\n",
    "def dis_different_dir(path):\n",
    "    # 目录下图片之间的距离\n",
    "    dirs = os.listdir(path)\n",
    "    image_set_list = []\n",
    "    image_hashing_value_set = []\n",
    "    for i in tqdm(dirs,ncols = 50):\n",
    "        image_hashing_value_set.append(image_hash(os.path.join(path, i)))\n",
    "    for i in range(len(image_hashing_value_set)):\n",
    "        for j in range(i+1,len(image_hashing_value_set)):\n",
    "            image_set_list.append(dist_img(image_hashing_value_set[i],image_hashing_value_set[j]))\n",
    "    return image_set_list,image_hashing_value_set\n",
    "\n",
    "def dis_similar_dir(path):\n",
    "    # 计算相同类型图片的距离\n",
    "    dir_rotation = os.listdir(path)\n",
    "    dis_similar = []\n",
    "    for i in dir_rotation:\n",
    "        if os.path.splitext(i)[1] == \".bmp\":\n",
    "#             print(os.path.join(path, i)) # 用于查看路径是否有中文\n",
    "            h1 = image_hash(os.path.join(path, i))\n",
    "            dir_temp = os.path.join(path,os.path.splitext(i)[0])\n",
    "            for j in tqdm(os.listdir(dir_temp),ncols = 50):\n",
    "                h2 = image_hash(os.path.join(dir_temp,j))\n",
    "                dis_similar.append(dist_img(h1,h2))\n",
    "    return dis_similar\n",
    "\n",
    "def my_auc(image_similar, image_different):\n",
    "    from scipy import integrate\n",
    "    sum1 = len(image_similar)\n",
    "    sum2 = len(image_different)\n",
    "    tpr = []\n",
    "    fpr = []\n",
    "    threshold_max = (max(max(image_similar), max(image_different)))\n",
    "    for threshold in range(1,threshold_max):\n",
    "        tpr_number = 0\n",
    "        fpr_number = 0\n",
    "        for i in image_similar:\n",
    "            if i < threshold:\n",
    "                tpr_number += 1\n",
    "        for j in image_different:\n",
    "            if j < threshold:\n",
    "                fpr_number += 1\n",
    "        tpr.append(tpr_number/sum1)\n",
    "        fpr.append(fpr_number/sum2)\n",
    "    return integrate.trapezoid(tpr,fpr)\n",
    "\n",
    "def stat_analysis(dir_path):\n",
    "    dirs = os.listdir(dir_path)\n",
    "    for i in dirs:\n",
    "        xlsx_path = os.path.join(dir_path, i)\n",
    "        data = pd.read_excel(xlsx_path,header = 0)[0]\n",
    "        print(f\"{i}的最小值：{min(data)}最大值：{max(data)}平均值：{np.mean(data)}\")\n",
    "\n",
    "def auc_analysis(dir_path):\n",
    "    data_similar_rotation_2 = pd.read_excel(os.path.join(dir_path,\"image_similar_distance_2_标准化.xlsx\"),header = 0)[0]\n",
    "    data_similar_rotation_90 = pd.read_excel(os.path.join(dir_path,\"image_similar_distance_90_标准化.xlsx\"),header = 0)[0]\n",
    "    data_different_set_200 = pd.read_excel(os.path.join(dir_path,\"image_different_distance_200_标准化.xlsx\"),header = 0)[0]\n",
    "    data_different_set_1000 = pd.read_excel(os.path.join(dir_path,\"image_different_distance_1000_标准化.xlsx\"),header = 0)[0]\n",
    "    print(f\"旋转2°和set 200的auc值{my_auc(data_similar_rotation_2,data_different_set_200)}\")\n",
    "    print(f\"旋转2°和set 1000的auc值{my_auc(data_similar_rotation_2,data_different_set_1000)}\")\n",
    "    print(f\"旋转90°和set 200的auc值{my_auc(data_similar_rotation_90,data_different_set_200)}\")\n",
    "    print(f\"旋转90°和set 1000的auc值{my_auc(data_similar_rotation_90,data_different_set_1000)}\")\n",
    "\n",
    "def copy_dectection_result(query_path, test_path):\n",
    "    import glob\n",
    "    query_hash = []\n",
    "    test_hash = [] # 后 160 的结果是复制图像的结果\n",
    "    dist_set = []\n",
    "    for i in tqdm(os.listdir(query_path), ncols = 50):\n",
    "        query_hash.append(image_hash(os.path.join(query_path, i)))\n",
    "    for i in tqdm(os.listdir(os.path.join(test_path, \"different_dataset\")), ncols =50):\n",
    "        test_hash.append(image_hash(os.path.join(test_path, \"different_dataset\", i)))\n",
    "    for root, dirs, files in os.walk(os.path.join(test_path, \"copy_attack\")):\n",
    "        for file in tqdm(glob.glob(os.path.join(root, '*.[a-zA-Z]*')), ncols = 50):  # 你可以根据需要修改文件类型，例如 *.png, *.gif 等 \n",
    "            test_hash.append(image_hash(file))\n",
    "    print(len(test_hash), len(query_hash))\n",
    "    print(\"开始计算哈希距离\")\n",
    "    for i in tqdm(test_hash, ncols = 50):\n",
    "        for j in query_hash:\n",
    "            dist_set.append(dist_img(i, j))\n",
    "    pd.DataFrame(dist_set).to_excel(\"./复制检测结果/复制检测距离结果（1160）.xlsx\", index = False)\n",
    "    \n",
    "def P_R_result(path):\n",
    "    dist_set = np.array(pd.read_excel(path))\n",
    "    min_dist = min(dist_set)\n",
    "    max_dist = max(dist_set)\n",
    "    P = []\n",
    "    R = []\n",
    "    for threshold in np.linspace(min_dist, max_dist, 15):\n",
    "        diff_res = [1 if np.all(dist_set[i:i+10] > threshold) else 0 for i in np.arange(0, 9900, 10)]\n",
    "        copy_res = [1 if np.any(dist_set[i:i+10] <= threshold) else 0 for i in np.arange(9900, 11600, 10)]\n",
    "        # diff_res = [1 if np.all(dist_set[i:i+10] > threshold) else 0 for i in np.arange(0, 10000, 10)]\n",
    "        # copy_res = [1 if np.any(dist_set[i:i+10] <= threshold) else 0 for i in np.arange(10000, 11600, 10)]\n",
    "        TP = sum(copy_res)\n",
    "        # FN = 160 - TP\n",
    "        FN = 170 - TP\n",
    "        FP = 990 - sum(diff_res)\n",
    "        P.append(TP / (TP + FP))\n",
    "        R.append(TP / (TP + FN))\n",
    "    return np.linspace(min_dist, max_dist, 15), P, R\n",
    "\n",
    "def copy_dectection_result(dataset_path):\n",
    "    query_path = os.path.join(dataset_path, \"query_dataset\")\n",
    "    attack_path = os.path.join(dataset_path, \"test_dataset\", \"copy_attack\")\n",
    "    different_path = os.path.join(dataset_path, \"test_dataset\", \"different_dataset\")\n",
    "    result = pd.DataFrame()\n",
    "    for i in tqdm(os.listdir(query_path), ncols = 50):\n",
    "        temp = []\n",
    "        h1 = image_hash(os.path.join(query_path, i))\n",
    "        img_attack_path = os.path.join(attack_path, i.split(\".\")[0])\n",
    "        for j in os.listdir(img_attack_path):\n",
    "            h2 = image_hash(os.path.join(img_attack_path, j))\n",
    "            temp.append(dist_img(h1, h2))\n",
    "        for j in os.listdir(different_path):\n",
    "            h2 = image_hash(os.path.join(different_path, j))\n",
    "            temp.append(dist_img(h1, h2))\n",
    "        result[i] = temp\n",
    "    result.to_excel(\"./复制检测结果/第二次/result.xlsx\", index = False)\n",
    "    return result\n",
    "\n",
    "def cal_mAP(result_path):\n",
    "    result = pd.read_excel(result_path)\n",
    "    mAP = 0\n",
    "    for i in result:\n",
    "        now_10 = result[i][:10]\n",
    "        sorted_list = list(result[i])\n",
    "        sorted_list.sort()\n",
    "        max_10 = sorted_list[:10] # 这里是从小到大进行排序\n",
    "        mAP += cal_ap(now_10, max_10)\n",
    "    return mAP / 16\n",
    "\n",
    "def cal_ap(now_10, max_10):\n",
    "    AP = 0\n",
    "    bool_list = []\n",
    "    for i in now_10:\n",
    "        if i in max_10:\n",
    "            bool_list.append(1)\n",
    "        else:\n",
    "            bool_list.append(0)\n",
    "    for index, i in enumerate(bool_list):\n",
    "        AP += i * (sum(bool_list[:index+1]) / (index + 1))\n",
    "    return AP / len(now_10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "b2f51060-49b5-46ad-a064-5b29e415d242",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-02T10:56:39.920197Z",
     "iopub.status.busy": "2024-05-02T10:56:39.919964Z",
     "iopub.status.idle": "2024-05-02T11:29:23.947752Z",
     "shell.execute_reply": "2024-05-02T11:29:23.944415Z",
     "shell.execute_reply.started": "2024-05-02T10:56:39.920177Z"
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|████████████| 16/16 [32:42<00:00, 122.65s/it]\n"
     ]
    }
   ],
   "source": [
    "result = copy_dectection_result(\"../new_data/copy_detection_dataset_2\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "dcf41a86-2ad7-4657-8977-dc767eb640d1",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-20T13:06:00.799109Z",
     "iopub.status.busy": "2024-04-20T13:06:00.797722Z",
     "iopub.status.idle": "2024-04-20T13:06:07.772064Z",
     "shell.execute_reply": "2024-04-20T13:06:07.770570Z",
     "shell.execute_reply.started": "2024-04-20T13:06:00.799044Z"
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|████████████| 10/10 [00:00<00:00, 138.70it/s]\n",
      "100%|██████████| 990/990 [00:05<00:00, 190.80it/s]\n",
      "0it [00:00, ?it/s]\n",
      "100%|████████████| 10/10 [00:00<00:00, 191.03it/s]\n",
      "100%|████████████| 10/10 [00:00<00:00, 192.66it/s]\n",
      "100%|████████████| 10/10 [00:00<00:00, 210.19it/s]\n",
      "100%|████████████| 10/10 [00:00<00:00, 214.73it/s]\n",
      "100%|████████████| 10/10 [00:00<00:00, 238.17it/s]\n",
      "100%|████████████| 10/10 [00:00<00:00, 113.10it/s]\n",
      "100%|████████████| 10/10 [00:00<00:00, 276.71it/s]\n",
      "100%|████████████| 10/10 [00:00<00:00, 283.13it/s]\n",
      "100%|████████████| 10/10 [00:00<00:00, 272.03it/s]\n",
      "100%|████████████| 10/10 [00:00<00:00, 273.61it/s]\n",
      "100%|████████████| 10/10 [00:00<00:00, 276.28it/s]\n",
      "100%|████████████| 10/10 [00:00<00:00, 207.11it/s]\n",
      "100%|████████████| 10/10 [00:00<00:00, 211.25it/s]\n",
      "100%|████████████| 10/10 [00:00<00:00, 270.01it/s]\n",
      "100%|████████████| 10/10 [00:00<00:00, 199.45it/s]\n",
      "100%|████████████| 10/10 [00:00<00:00, 205.32it/s]\n",
      "100%|████████████| 10/10 [00:00<00:00, 212.72it/s]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1160 10\n",
      "开始计算哈希距离\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|██████| 1160/1160 [00:00<00:00, 18370.93it/s]\n"
     ]
    }
   ],
   "source": [
    "copy_dectection_result(\"../new_data/copy_detection_dataset/query_dataset/\", \"../new_data/copy_detection_dataset/test_dataset/\")\n",
    "theshold, P, R = P_R_result(\"./复制检测结果/复制检测距离结果（1160）.xlsx\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "327d87a3-9904-461d-975e-6d47665e67bf",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-20T13:06:44.350292Z",
     "iopub.status.busy": "2024-04-20T13:06:44.349585Z",
     "iopub.status.idle": "2024-04-20T13:06:44.357236Z",
     "shell.execute_reply": "2024-04-20T13:06:44.356040Z",
     "shell.execute_reply.started": "2024-04-20T13:06:44.350249Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0.15294117647058825, 0.3352941176470588, 0.5588235294117647, 0.7058823529411765, 0.8529411764705882, 0.9294117647058824, 0.9705882352941176, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]\n",
      "[1.0, 1.0, 1.0, 0.9230769230769231, 0.5753968253968254, 0.3056092843326886, 0.18792710706150342, 0.15232974910394265, 0.1474414570685169, 0.14655172413793102, 0.14655172413793102, 0.14655172413793102, 0.14655172413793102, 0.14655172413793102, 0.14655172413793102]\n"
     ]
    }
   ],
   "source": [
    "print(R)\n",
    "print(P)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "e9a8a210-d2e7-4cb0-925e-7c43b9ce42f3",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-20T13:06:24.416103Z",
     "iopub.status.busy": "2024-04-20T13:06:24.415073Z",
     "iopub.status.idle": "2024-04-20T13:06:24.617068Z",
     "shell.execute_reply": "2024-04-20T13:06:24.615622Z",
     "shell.execute_reply.started": "2024-04-20T13:06:24.416038Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "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kyZN8mid+FZrwsgvfvEL44orrrhg2+zZs43p06d7rC4u07RDbW2tsrKylJKS0rTNarUqJSVFW7ZsadV7VFVVyeFwKDo62lNlQm3v1VNPPaXY2Fj97Gc/64gyA15b+vT+++8rOTlZ8+fPV1xcnIYPH65nn31W9fX1HVV2QGpLryZOnKisrKymSzm5ublat26dbrjhhg6pGa2zZcuWC/oqSdOnT2/177W28ImF8rxVaWmp6uvrFRcXd8H2uLg47d27t1Xv8cgjj6hnz54XNR7u1ZZebd68WS+//LKys7M7oEJIbetTbm6uPvnkE915551at26dcnJy9OCDD8rhcCgtLa0jyg5IbenVHXfcodLSUl199dUyDEN1dXV64IEH9Nhjj3VEyWilwsLCZvtaXl6us2fPqlOnTm7/TM6MmOi5557T6tWr9c477ygsLMzscnCeiooKzZkzRytXrlRMTIzZ5eASnE6nYmNj9cc//lFjxozR7NmztXjxYr344otml4Z/kZmZqWeffVYvvPCCduzYobfffltr167V008/bXZpMBlnRtohJiZGNptNRUVFF2wvKipSfHz8JY/97W9/q+eee04ff/yxRowY4ckyIdd7dfDgQR06dEizZs1q2uZ0OiVJQUFB2rdvnwYMGODZogNQW36mEhISFBwcLJvN1rRt2LBhKiwsVG1trUJCQjxac6BqS6+eeOIJzZkzR/fee68k6corr1RlZaXuv/9+LV68WFYr/z72BvHx8c32NTIy0iNnRSTOjLRLSEiIxowZo4yMjKZtTqdTGRkZSk5ObvG4X//613r66ae1fv16jR07tiNKDXiu9mro0KH6+uuvlZ2d3fTnpptu0pQpU5SdnS273d6R5QeMtvxMTZo0STk5OU1hUZL279+vhIQEgogHtaVXVVVVFwWOxhBpsEya10hOTr6gr5KUnp5+yd9r7eaxW2MDxOrVq43Q0FDjlVdeMXbv3m3cf//9RteuXY3CwkLDMAxjzpw5xqOPPtq0/3PPPWeEhIQYb731llFQUND0p6KiwqxvIWC42qt/xTRNx3C1T0eOHDEiIiKMBQsWGPv27TM+/PBDIzY21vjVr35l1rcQMFztVVpamhEREWH89a9/NXJzc40NGzYYAwYMMG677TazvoWAUFFRYezcudPYuXOnIclYtmyZsXPnTuPw4cOGYRjGo48+asyZM6dp/8bR3v/4j/8w9uzZYyxfvpzRXl/whz/8wejTp48REhJijB8/3vj888+bXrvmmmuMe+65p+nrvn37GpIu+pOWltbxhQcgV3r1rwgjHcfVPn322WfGhAkTjNDQUKN///7GM888Y9TV1XVw1YHJlV45HA7jl7/8pTFgwAAjLCzMsNvtxoMPPmicPHmy4wsPIBs3bmz2905jb+655x7jmmuuueiYUaNGGSEhIUb//v2NP/3pTx6t0WIYnBsDAADm4Z4RAABgKsIIAAAwFWEEAACYijACAABMRRgBAACmIowAAABTEUYAAICpCCMAAMBUhBEAAGAqwggAADAVYQQAAJiKMAIAAEz1/wHpgpVRpI/C2QAAAABJRU5ErkJggg==",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.plot(R, P,  \"-o\")\n",
    "plt.grid()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "e8fdd92d-4018-4290-8c20-3058838b2c9c",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-20T13:04:29.843931Z",
     "iopub.status.busy": "2024-04-20T13:04:29.842646Z",
     "iopub.status.idle": "2024-04-20T13:04:29.918838Z",
     "shell.execute_reply": "2024-04-20T13:04:29.917116Z",
     "shell.execute_reply.started": "2024-04-20T13:04:29.843868Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "10"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "h1 = image_hash(\"../data/rotation_2/Airplane/Airplane_ROTSCALE_1.bmp\")\n",
    "# h2 = image_hash(\"../data/mandrill512.tif\")\n",
    "h2 = image_hash(\"../data/rotation_2/Airplane.bmp\")\n",
    "dist_img(h1,h2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "id": "280d08c5",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-12-06T03:06:29.525926Z",
     "start_time": "2023-12-06T03:06:29.514955Z"
    },
    "execution": {
     "iopub.execute_input": "2024-01-07T11:49:17.665813Z",
     "iopub.status.busy": "2024-01-07T11:49:17.664093Z",
     "iopub.status.idle": "2024-01-07T11:49:51.264157Z",
     "shell.execute_reply": "2024-01-07T11:49:51.262730Z",
     "shell.execute_reply.started": "2024-01-07T11:49:17.665729Z"
    },
    "scrolled": true,
    "tags": []
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|████████████| 57/57 [00:00<00:00, 186.63it/s]\n",
      "100%|████████████| 57/57 [00:00<00:00, 205.30it/s]\n",
      "100%|████████████| 57/57 [00:00<00:00, 219.07it/s]\n",
      "100%|████████████| 57/57 [00:00<00:00, 261.22it/s]\n",
      "100%|████████████| 57/57 [00:00<00:00, 267.62it/s]\n",
      "100%|████████████| 57/57 [00:00<00:00, 268.28it/s]\n",
      "100%|████████████| 57/57 [00:00<00:00, 263.09it/s]\n",
      "100%|████████████| 57/57 [00:00<00:00, 269.52it/s]\n",
      "100%|████████████| 44/44 [00:00<00:00, 264.48it/s]\n",
      "100%|████████████| 16/16 [00:00<00:00, 264.80it/s]\n",
      "100%|████████████| 44/44 [00:00<00:00, 268.04it/s]\n",
      "100%|████████████| 16/16 [00:00<00:00, 268.37it/s]\n",
      "100%|████████████| 44/44 [00:00<00:00, 269.08it/s]\n",
      "100%|████████████| 16/16 [00:00<00:00, 109.15it/s]\n",
      "100%|████████████| 44/44 [00:00<00:00, 209.12it/s]\n",
      "100%|████████████| 16/16 [00:00<00:00, 250.44it/s]\n",
      "100%|████████████| 44/44 [00:00<00:00, 184.20it/s]\n",
      "100%|████████████| 16/16 [00:00<00:00, 156.47it/s]\n",
      "100%|███████████| 200/200 [00:02<00:00, 71.55it/s]\n",
      "100%|█████████| 1000/1000 [00:10<00:00, 99.19it/s]\n"
     ]
    }
   ],
   "source": [
    "data_similar_rotation_2 = dis_similar_dir(\"../data/rotation_2/\")\n",
    "pd.DataFrame(data_similar_rotation_2).to_excel(\"./结果/四元数Y空间结果/image_similar_distance_2_标准化.xlsx\",index = False)\n",
    "\n",
    "data_similar_rotation_90 = dis_similar_dir(\"../data/rotation_90/\")\n",
    "pd.DataFrame(data_similar_rotation_90).to_excel(\"./结果/四元数Y空间结果/image_similar_distance_90_标准化.xlsx\",index = False)\n",
    "\n",
    "data_different_set_200,_ = dis_different_dir(\"../data/Image Set 200/\")\n",
    "pd.DataFrame(data_different_set_200).to_excel(\"./结果/四元数Y空间结果/image_different_distance_200_标准化.xlsx\",index = False)\n",
    "\n",
    "data_different_set_1000,_ = dis_different_dir(\"../data/Image Set 1000/\")\n",
    "pd.DataFrame(data_different_set_1000).to_excel(\"./结果/四元数Y空间结果/image_different_distance_1000_标准化.xlsx\",index = False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "id": "f1f6a015-f8a5-494a-bbf2-d07d1389227c",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-01-07T11:49:51.465526Z",
     "iopub.status.busy": "2024-01-07T11:49:51.465275Z",
     "iopub.status.idle": "2024-01-07T11:50:13.852532Z",
     "shell.execute_reply": "2024-01-07T11:50:13.851541Z",
     "shell.execute_reply.started": "2024-01-07T11:49:51.465500Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "image_similar_distance_2_标准化.xlsx的最小值：0最大值：20平均值：2.960526315789474\n",
      "image_similar_distance_90_标准化.xlsx的最小值：0最大值：36平均值：5.733333333333333\n",
      "image_different_distance_200_标准化.xlsx的最小值：10最大值：56平均值：30.962010050251255\n",
      "image_different_distance_1000_标准化.xlsx的最小值：2最大值：60平均值：30.638186186186186\n",
      "旋转2°和set 200的auc值0.9996112690646214\n",
      "旋转2°和set 1000的auc值0.9993583495776478\n",
      "旋转90°和set 200的auc值0.9537484087102177\n",
      "旋转90°和set 1000的auc值0.9506797797797797\n"
     ]
    }
   ],
   "source": [
    "stat_analysis(\"./结果/四元数Y空间结果/\")\n",
    "auc_analysis(\"./结果/四元数Y空间结果/\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "5ed33d2b-7fd9-4a66-aa4a-dab1b5da2ecf",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-01-04T09:22:15.586007Z",
     "iopub.status.busy": "2024-01-04T09:22:15.585784Z",
     "iopub.status.idle": "2024-01-04T09:22:18.143379Z",
     "shell.execute_reply": "2024-01-04T09:22:18.142550Z",
     "shell.execute_reply.started": "2024-01-04T09:22:15.585976Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "image/png": "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4QXrhx9+sJ566inL39/f+vbbb1u58vbF2+t89913W8uWLbN27dpl7d6927r33nut0NBQ65///GcrV97+eHutz9m/f78VGxtrjRgxwrr99ttbp9h2zNvrXFVVZSUnJ1s333yztW3bNmv//v3Wpk2brLy8vFauvH3x9jq//fbblsPhsN5++21r//791qeffmpFR0dbM2fObOXK25d169ZZc+bMsT744ANLkvXhhx9etH1BQYEVFBRkZWZmWj/88IP18ssvW35+ftb69etbrMYOHUaGDh1qzZgxw/25pqbGiomJsbKysuptP2HCBOuWW27xWJeSkmI98MADLVpne+ftdb7Q2bNnreDgYGvlypUtVWKH0ZxrffbsWWvYsGHWG2+8YU2ePJkw0gTeXudXX33V6tmzp1VdXd1aJXYI3l7nGTNmWL/97W891mVmZlrDhw9v0To7kqaEkccff9zq16+fx7qMjAwrPT29xerqsMM01dXVys3NVVpamnudr6+v0tLSlJOTU+82OTk5Hu0lKT09vcH2aN51vtDJkyd15swZde3ataXK7BCae62feeYZRUZG6r777muNMtu95lznjz/+WKmpqZoxY4acTqf69++vhQsXqqamprXKbneac52HDRum3Nxc91BOQUGB1q1bp5tvvrlVarYLE9+F7eJFec1RWlqqmpoaOZ1Oj/VOp1N79uypd5vi4uJ62xcXF7dYne1dc67zhZ544gnFxMTU+eOHp+Zc623btunNN99UXl5eK1TYMTTnOhcUFGjjxo265557tG7dOu3bt08PPvigzpw5o3nz5rVG2e1Oc67z3XffrdLSUt14442yLEtnz57V9OnT9eSTT7ZGybbR0Hehy+XSqVOn1Llz58t+zA7bM4L2YdGiRVq9erU+/PBDBQYGmi6nQ6moqNDEiRP1+uuvKyIiwnQ5HVptba0iIyP12muvKSkpSRkZGZozZ46WL19uurQOZdOmTVq4cKFeeeUV7dy5Ux988IHWrl2rZ5991nRpuEQdtmckIiJCfn5+Kikp8VhfUlKiqKioereJioryqj2ad53PWbx4sRYtWqT/+7//08CBA1uyzA7B22udn5+vn376SePGjXOvq62tlSR16tRJP/74oxISElq26HaoOX/T0dHR8vf3l5+fn3tdnz59VFxcrOrqagUEBLRoze1Rc67z008/rYkTJ2rq1KmSpAEDBqiyslL333+/5syZI19f/vv6cmjouzAkJKRFekWkDtwzEhAQoKSkJGVnZ7vX1dbWKjs7W6mpqfVuk5qa6tFekjZs2NBgezTvOkvSCy+8oGeffVbr169XcnJya5Ta7nl7rXv37q1vv/1WeXl57uW2227T6NGjlZeXp7i4uNYsv91ozt/08OHDtW/fPnfYk6S9e/cqOjqaINKA5lznkydP1gkc5wKgxWvWLhsj34UtdmtsG7B69WrL4XBYb731lvXDDz9Y999/vxUWFmYVFxdblmVZEydOtGbNmuVu/8UXX1idOnWyFi9ebO3evduaN28ej/Y2gbfXedGiRVZAQID1/vvvW4cPH3YvFRUVpk6h3fD2Wl+Ip2maxtvrfPDgQSs4ONh66KGHrB9//NH65JNPrMjISOu5554zdQrtgrfXed68eVZwcLD13//931ZBQYH12WefWQkJCdaECRNMnUK7UFFRYe3atcvatWuXJclasmSJtWvXLuvAgQOWZVnWrFmzrIkTJ7rbn3u097HHHrN2795tLVu2jEd7L9XLL79sXXXVVVZAQIA1dOhQ66uvvnL/btSoUdbkyZM92r/77rvWtddeawUEBFj9+vWz1q5d28oVt0/eXOerr77aklRnmTdvXusX3g55+zd9PsJI03l7nb/88ksrJSXFcjgcVs+ePa0FCxZYZ8+ebeWq2x9vrvOZM2esf//3f7cSEhKswMBAKy4uznrwwQet48ePt37h7cjnn39e77+5567t5MmTrVGjRtXZZtCgQVZAQIDVs2dP6z//8z9btEYfy6JvCwAAmNNh7xkBAADtA2EEAAAYRRgBAABGEUYAAIBRhBEAAGAUYQQAABhFGAEAAEYRRgAAgFGEEQAAYBRhBAAAGEUYAQAARhFGAACAUf8P+7j8NNulFNUAAAAASUVORK5CYII=",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from sklearn.metrics import roc_curve, auc\n",
    "roc_auc = auc(fpr,tpr)   # 准确率代表所有正确的占所有数据的比值\n",
    "plt.plot(fpr, tpr, 'k--', label='ROC (area = {0:.2f})'.format(roc_auc), lw=2)\n",
    "plt.savefig(\"旋转2的roc.png\",dpi=600)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "image",
   "language": "python",
   "name": "image"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.18"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
